/* Main Pipeline Cycle Processor Controller
 * 
 * This module takes in a 32-bit instruction code and breaks it
 * into an Op (Operation) code and Funct (Function) code.
 * 
 * Control signals assigned from these codes as follows:
 *
 * RegDst   - [2 bits] Switches between Rd & Rt depending on R format or not.
 *
 * ALUsrc   - Controls whether the b-side of the ALU will take in
 *          an immediate or busB.
 * RegWrSrc - [2 bits] Selects between the ALU, the memory out, and the
 *          PC.
 * RegWrite - An enable signal to determine if busW will be 
 *          written to a register.
 * MemWrite - An enable singal to determine if busB will be
 *          written to the memory address at ALUout.
 * BranchOut- [2 bits] Causes Proc to branch on equal if 01
 *                                    branch on not equal if 10.
 * Jump     - [2 bits] Does not jump if 0
 *                     Jumps to instruction address if 01
 *										 Jumps to address on busA if 10.
 * ALUctr   - [6 bits] Gives the appropriate arithmetic command
 *            to the ALU.
 * ExtOp    - Causes the extender to sign-extend or zero-fill.
 *
 */				 

module Controller (Instruction[31:0],RegDst,ALUsrc,RegWrSrc,RegWrite,MemRead,MemWrite,Branch,Jump,ALUctr,ExtOp);
   parameter T_data = 20;

   input [31:0] Instruction;

	 output ALUsrc,RegWrite,MemWrite,ExtOp, MemRead;
	 output [1:0] RegDst,RegWrSrc,Branch,Jump;
   output [5:0] ALUctr;

   wire [5:0] Op, Funct;
	 wire ALUsrc,RegWrite,MemWrite,ExtOp;
	 wire [1:0]  RegDst,RegWrSrc,Branch,Jump;
   reg [5:0] ALUctr;
	 
	 assign Op = Instruction[31:26];
	 assign Funct = Instruction[5:0];

   assign RegDst[1] = (Op== 3),
	        RegDst[0] = (~|Op & Funct != 8);

   assign RegWrite = (~|Op & (Funct != 6'b001000))
	                  |(!Op[5]&!Op[4]&Op[3]&!Op[2]&!Op[1])
	                  |(!Op[5]&!Op[4]&Op[3]&Op[2])
	                  |(!Op[5]&!Op[4]&Op[3]&!Op[2]&Op[1])
	                  |(!Op[5]&!Op[4]&!Op[3]&!Op[2]&Op[1]&Op[0])
	                  |(!Op[5]&Op[4]&!Op[3]&Op[2]&(Op[1]~^ Op[0]));

   assign MemRead= (!Op[5]&Op[4]&!Op[3]&Op[2]&Op[1]&Op[0]);

   assign MemWrite= (Op[5]&!Op[4]&Op[3]&!Op[2]&(Op[1]~^Op[0]));

   assign Branch[0] = (!Op[5]&!Op[4]&!Op[3]&Op[2]&!Op[1]&!Op[0]), 
          Branch[1] = (!Op[5]&!Op[4]&!Op[3]&Op[2]&!Op[1]&Op[0]);

   assign RegWrSrc[0] = (Op[5]&!Op[4]&!Op[3]&!Op[2]&(Op[1] ~^ Op[0])),
	        RegWrSrc[1] = (!Op[5]&!Op[4]&!Op[3]&!Op[2]&Op[1]&Op[0]); 

   assign Jump[0] = (!Op[5]&!Op[4]&!Op[3]&!Op[2]&Op[1]&!Op[0]) 
	                | (!Op[5]&!Op[4]&!Op[3]&!Op[2]&Op[1]&Op[0]), 
	        Jump[1] = (~|Op) & (!Funct[5]&!Funct[4]&Funct[3]&!Funct[2]&!Funct[1]&!Funct[0]);

   assign ExtOp = (!Op[5]&!Op[4]&Op[3]&!Op[2]&!Op[1]&!Op[0])  //addi
              | (!Op[5]&!Op[4]&Op[3]&!Op[2]&!Op[1]&Op[0])     //addiu 
              | (!Op[5]&!Op[4]&Op[3]&Op[2]&Op[1]&Op[0])       //lui
              | (!Op[5]&!Op[4]&Op[3]&!Op[2]&Op[1]&!Op[0])     //slti
              | (!Op[5]&Op[4]&!Op[3]&Op[2]&!Op[1]&!Op[0])     //lb
              | (!Op[5]&!Op[4]&!Op[3]&Op[2]&!Op[1]&!Op[0])    //beq
              | (!Op[5]&!Op[4]&!Op[3]&Op[2]&!Op[1]&Op[0])     //bne
        		  | (!Op[5]&Op[4]&!Op[3]&Op[2]&Op[1]&Op[0]);      //lw

   assign ALUsrc = (!Op[5]&!Op[4]&Op[3])
                  |(!Op[5]&Op[4]&!Op[3]&Op[2]&(!Op[1]~^Op[0]))
                  |(!Op[5]&Op[4]&Op[3]&Op[2]&!Op[1]&!Op[0]) 
                  |Op[5];

always @(Op)
if(Op==0)
	assign ALUctr = Funct;
else
	 assign ALUctr = {{(~Op[5] & ~Op[4] & ~Op[3] & Op[2] & ~Op[1])
	                  | (~Op[5] & ~Op[4] & Op[3] & ~Op[2])
                    | (~Op[5] & ~Op[4] & Op[3] & Op[2] & (Op[1] ~& Op[0]))
                    | (~Op[5] & Op[4] & ~Op[3] & Op[2] & (Op[1] ~^ Op[0]))
                    | (~Op[5] & Op[4] & Op[3] & Op[2] & ~Op[1] & ~Op[0])
                    | (Op[5] & ~Op[4] & Op[3] & ~Op[2] & Op[1] & Op[0])},
	                 {(1'b0)},
	                 {(~Op[5] & ~Op[4] & Op[3] & ~Op[2] & Op[1])},
	                 {(~Op[5] & ~Op[4] & Op[3] & Op[2] & ~Op[1])
                    | (~Op[5] & ~Op[4] & Op[3] & Op[2] & Op[1] & ~Op[0])},
	                 {(~Op[5] & ~Op[4] & ~Op[3] & Op[2] & ~Op[1])
                    | (~Op[5] & ~Op[4] & Op[3] & ~Op[2] & Op[1])
                    | (~Op[5] & ~Op[4] & Op[3] & Op[2] & Op[1] & ~Op[0])},
	                 {(~Op[5] & ~Op[4] & Op[3] & ~Op[2] & Op[0])
                    | (~Op[5] & ~Op[4] & Op[3] & Op[2] & Op[0])}};

always@(Instruction[31:0] or RegDst or ALUsrc or RegWrSrc or RegWrite or MemWrite or Branch or Jump or ALUctr or ExtOp)
	 begin
	 $display("Control Outputs");
	 $display($time," Op=%d Funct=%d ALUctr=%d RegDst=%b, ALUsrc=%b, RegWrSrc=%b, RegWrite=%b, MemWrite=%b, Branch=%b, Jump=%b, ExtOp=%b",
	               Op,Funct,ALUctr,RegDst,ALUsrc,RegWrSrc,RegWrite,
	 					     MemWrite,Branch,Jump,ExtOp);
	 end

endmodule


/*
module TestController;

	 reg [31:0] Instruction;
	 reg Zero;

	 wire [5:0] Op, Funct;
	 wire RegDst,ALUsrc,RegWrite,MemWrite,ExtOp;
	 wire [1:0] RegWrSrc,BranchOut,Jump;
   wire [5:0] ALUctr;

	 assign Op = Instruction[31:26];
	 assign Funct = Instruction[5:0];

	 Controller CtrTest(Instruction,RegDst,ALUsrc,RegWrSrc,RegWrite,MemWrite,BranchOut,Jump,ALUctr,ExtOp,Zero);

	 initial begin

	 $monitor($time,"Op=%d Funct=%d ALUctr=%d RegDst=%b, ALUsrc=%b, RegWrSrc=%b, RegWrite=%b, MemWrite=%b, BranchOut=%b, Jump=%b, ExtOp=%b",
	               Op,Funct,ALUctr,RegDst,ALUsrc,RegWrSrc,RegWrite,
	 					MemWrite,BranchOut,Jump,ExtOp);
	 Instruction = 0;
   Zero = 0;
// Run through all Function codes
   #10 Instruction=0;
   #10 Instruction=2;
   #10 Instruction=3;
   #10 Instruction=8;
   #10 Instruction=32;
   #10 Instruction=33;
   #10 Instruction=34;
   #10 Instruction=35;
   #10 Instruction=36;
   #10 Instruction=37;
   #10 Instruction=38;
   #10 Instruction=42;
   #10 Instruction=43;

   #10 Instruction[31:26]=2;
   #10 Instruction[31:26]=3;
   #10 Instruction[31:26]=4;
   #10 Instruction[31:26]=5;
   #10 Zero = 1;
   #10 Instruction[31:26]=4;
   #10 Instruction[31:26]=5;
   #10 Instruction[31:26]=8;
   #10 Instruction[31:26]=9;
   #10 Instruction[31:26]=10;
   #10 Instruction[31:26]=11;
   #10 Instruction[31:26]=12;
   #10 Instruction[31:26]=13;
   #10 Instruction[31:26]=14;
   #10 Instruction[31:26]=15;
   #10 Instruction[31:26]=32;
   #10 Instruction[31:26]=35;
   #10 Instruction[31:26]=40;
   #10 Instruction[31:26]=43;
	 #10 $finish;		
	 end
endmodule
*/
